#include <iostream>
#include <assert.h>
#include <string>

using std::cout;
using std::endl;
using std::string;

//由于模板类的特性，每个不同的模板参数会导致生成一个独立的类定义，
//Singleton<Point>、Singleton<Computer>是不同的单例模式(不同的类)，它们各自管理着不同类型的单例对象。
//所以可以创建两个单例模式对象

class Point{
public:
    Point(int x, int y)
    : _x(x)
    , _y(y)
    {
        cout<<"Point()"<<endl;
    }

    ~Point(){
        cout<<"~Point()"<<endl;
    }

    void display(){
        cout<<_x<<","<<_y<<endl;
    }

private:
    int _x;
    int _y;
};


class Computer{
public:
    Computer(const string &brand, int price)
    : _brand(brand)
    , _price(price)
    {
        cout<<"Computer()"<<endl;
    }

    ~Computer(){
        cout<<"~Computer()"<<endl;
    }

    void display(){
        cout<<_brand<<","<<_price<<endl;
    }

private:
    string _brand;
    int _price;
};

template<class T>
class Singleton{
public:
    template<class ...Args>
    static T *getInstance(Args ...args){
        if(!_pInstance){
            _pInstance = new T(args...);
            _ar;//进入main函数，完成了模板推导后，这里才真正将ar实例化
        }
        else
            cout<<"不要申请两次"<<endl;
        return _pInstance;
    }

    static void destroy(){
        if(_pInstance){
            delete _pInstance;
            _pInstance = nullptr;
        }
        else
            cout<<"不要释放两次"<<endl;
    }

private:
    class AutoRelease
    {
    public: //构造函数和析构函数得是public，否则不能在类体外定义这个静态成员了
        AutoRelease(){
            cout<<"AutoRelease()"<<endl;
        }

        ~AutoRelease(){
            cout<<"~AutoRelease()"<<endl;
            if(_pInstance){
                delete _pInstance;
                _pInstance=nullptr;
            }
        }
    };

private:
    Singleton(){
        cout<<"Singleton()"<<endl;
    }
    
    ~Singleton(){
        cout<<"手动释放"<<endl;
    }

    static T * _pInstance;
    static AutoRelease _ar;
};

template<class T>
T* Singleton<T>::_pInstance = nullptr;

template<class T>
typename Singleton<T>::AutoRelease Singleton<T>::_ar;
//1、当使用模板类中的依赖类型名称时，编译器需要使用 typename 关键字来明确告诉编译器这是一个类型。
//这是因为在模板类中，依赖类型名称可能被误解为一个静态成员或者一个静态函数，而不是一个类型。
//2、这里虽然执行了auto的构造函数，但并没有真正完成_ar的实例化，
//因为模板的推导是在main函数里，只有知道了具体类型之后，才真正实例化ar

void test(){

    cout<<endl;
    cout<<"静态成员_ar在main之前就已经调用了构造函数"<<endl;
    Computer *pc1 = Singleton<Computer>::getInstance("Xiaomi", 6666);
    cout<<"为什么ar会实例化两次，因为有一种T，就实例化一次"<<endl;
    cout<<"这里Computer、Point两个T，ar就实例化两次"<<endl;
    cout<<"即使Computer、Point分开放在test1()、test2()也一样"<<endl;
    
    cout<<endl;
    Computer *pc2 = Singleton<Computer>::getInstance("Huawei", 8888);
    assert(pc1 == pc2);
    cout<<pc1<<endl;
    cout<<pc2<<endl;
    cout<<&pc1<<endl;
    cout<<&pc2<<endl;
    //pc相同，都指向单例模式，&pc则不同
    pc1->display();
    pc2->display();
    //Singleton<Computer>::destroy();   如果没有自动释放，可以这样手动释放

    cout<<"================================================="<<endl;

    Point *pt3 = Singleton<Point>::getInstance(1, 2);
    Point *pt4 = Singleton<Point>::getInstance(3, 4);
    cout<<pt3<<endl;
    cout<<pc1<<endl;
    assert(pt3 == pt4);
    pc1->display();
    pt3->display();
    
    cout<<"================================================="<<endl;

}

int main()
{
    test();
    return 0;
} 


